'use strict'; const { Document } = require('/document.js'); const { DocumentCommand } = require('/commands.js'); const { Dialog, DialogResult, UnitType } = require('/dialog.js'); const { DiffusionCurveSet, DiffusionFill, FillDescriptor } = require('/fills.js'); const { RGBA8 } = require('/colours.js'); const { Transform } = require('/geometry.js'); function isOk(result) { return (result?.value ?? result) === DialogResult.Ok.value; } function randomVividColour(rFactor, gFactor, bFactor) { const h = Math.random() * 360; const s = 0.7 + Math.random() * 0.3; const v = 0.6 + Math.random() * 0.4; const c = v * s, x = c * (1 - Math.abs((h / 60) % 2 - 1)), m = v - c; let r = 0, g = 0, b = 0; if (h < 60) { r = c; g = x; b = 0; } else if (h < 120) { r = x; g = c; b = 0; } else if (h < 180) { r = 0; g = c; b = x; } else if (h < 240) { r = 0; g = x; b = c; } else if (h < 300) { r = x; g = 0; b = c; } else { r = c; g = 0; b = x; } const rv = Math.min(255, Math.max(0, Math.round((r + m) * 255 * rFactor))); const gv = Math.min(255, Math.max(0, Math.round((g + m) * 255 * gFactor))); const bv = Math.min(255, Math.max(0, Math.round((b + m) * 255 * bFactor))); return RGBA8(rv, gv, bv, 255); } function applyDiffusionFill(node, curveCount, minRadius, maxRadius, rxFactor, ryFactor, blur, strength, rFactor, gFactor, bFactor) { const bounds = node.baseBox; const curveSet = DiffusionCurveSet.create(); for (let i = 0; i < curveCount; i++) { const cx = 0.05 + Math.random() * 0.90; const cy = 0.05 + Math.random() * 0.90; const rotation = Math.random() * Math.PI * 2; // Apply radius factors — clamp above 0.001 to avoid zero-radius error const rx = Math.max(0.001, (minRadius + Math.random() * (maxRadius - minRadius)) * rxFactor); const ry = Math.max(0.001, (minRadius + Math.random() * (maxRadius - minRadius)) * ryFactor); const innerColour = randomVividColour(rFactor, gFactor, bFactor); const outerColour = randomVividColour(rFactor, gFactor, bFactor); try { curveSet.addEllipse({ x: cx, y: cy }, rx, ry, rotation, innerColour, outerColour); } catch(e) {} } for (let i = 0; i < curveSet.curveCount; i++) { curveSet.setCurveBlur(i, Math.min(1.0, blur)); curveSet.setCurveStrength(i, Math.min(2.0, Math.max(0, strength))); } const fillTransform = Transform.multiply( Transform.createTranslate(bounds.x, bounds.y), Transform.createScale(bounds.width, bounds.height) ); const descriptor = FillDescriptor.create( DiffusionFill.create(curveSet), true, fillTransform, undefined, false ); node.brushFillInterface.fillDescriptor = descriptor; } // ---- MAIN ---- const doc = Document.current; if (!doc) { console.log('ERROR: No document open.'); } else { const selectedNodes = doc.selection.nodes.filter(n => n.brushFillInterface !== null).toArray(); if (selectedNodes.length === 0) { console.log('Please select one or more shapes first.'); } else { const dlg = Dialog.create('Diffusion Circle Fill'); const col = dlg.addColumn(); const g1 = col.addGroup('Circular Diffusion'); const countCtrl = g1.addUnitValueEditor('Circles (max 300)', UnitType.Number, UnitType.Number, 20, 1, 300).setPrecision(0); // const g2 = col.addGroup('Min radius (0–0.5)'); const minRCtrl = g1.addUnitValueEditor('Min radius (0–0.5)', UnitType.Number, UnitType.Number, 0.02, 0.01, 0.5).setPrecision(3); //const g3 = col.addGroup('Max radius (0–0.5)'); const maxRCtrl = g1.addUnitValueEditor('Max radius (0–0.5)', UnitType.Number, UnitType.Number, 0.2, 0.01, 0.5).setPrecision(3); // const g4 = col.addGroup('Radius X factor (0–10)'); const rxFactorCtrl = g1.addUnitValueEditor('Radius X factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); //const g5 = col.addGroup('Radius Y factor (0–10)'); const ryFactorCtrl = g1.addUnitValueEditor('Radius Y factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); //const g6 = col.addGroup('Blur (0–1)'); const blurCtrl = g1.addUnitValueEditor('Blur (0–1)', UnitType.Number, UnitType.Number, 0.3, 0.0, 1.0).setPrecision(2); //const g7 = col.addGroup('Strength (0–2)'); const strengthCtrl = g1.addUnitValueEditor('Strength (0–2)', UnitType.Number, UnitType.Number, 1.0, 0.0, 2.0).setPrecision(2); // const g8 = col.addGroup('Red channel factor (0–10)'); const rCtrl = g1.addUnitValueEditor('Red channel factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); // const g9 = col.addGroup('Green channel factor (0–10)'); const gCtrl = g1.addUnitValueEditor('Green channel factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); //const g10 = col.addGroup('Blue channel factor (0–10)'); const bCtrl = g1.addUnitValueEditor('Blue channel factor (0–10)', UnitType.Number, UnitType.Number, 1.0, 0.0, 10.0).setPrecision(2); dlg.initialWidth = 420; const result = dlg.runModal(); if (isOk(result)) { const count = Math.min(100, Math.max(1, Math.round(countCtrl.value))); const minR = Math.min(minRCtrl.value, maxRCtrl.value); const maxR = Math.max(minRCtrl.value, maxRCtrl.value); const rxFactor = rxFactorCtrl.value; const ryFactor = ryFactorCtrl.value; const blur = blurCtrl.value; const strength = strengthCtrl.value; const rFactor = rCtrl.value; const gFactor = gCtrl.value; const bFactor = bCtrl.value; const spread = doc.currentSpread; doc.executeCommand(DocumentCommand.createSetCurrentSpread(spread)); for (const node of selectedNodes) { applyDiffusionFill(node, count, minR, maxR, rxFactor, ryFactor, blur, strength, rFactor, gFactor, bFactor); } console.log(`Done! Applied to ${selectedNodes.length} node(s).`); } } }